package se.liu.oschi129.game.objects.enemies;

import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.util.Random;

import se.liu.oschi129.game.objects.ObjectPlayer;
import se.liu.oschi129.game.objects.enemies.projectiles.ProjectileFactory;
import se.liu.oschi129.game.objects.enemies.projectiles.ProjectileFactory01;
import se.liu.oschi129.game.setspace.AnimatedSetToad;
import se.liu.oschi129.shapefactory.ShapeFactory;
import se.liu.oschi129.timer.Timer;
import se.liu.oschi129.world.model.World;
import se.liu.oschi129.world.objects.WorldMovableCharacterObject;
import se.liu.oschi129.world.objects.WorldObject;

/**
 * This is an enemy toad. It will throw projectiles towards the player in order to hit him.
 * 
 * @author oschi129
 */
public class ObjectEnemyToadThrowing extends WorldMovableCharacterObject implements EnemyObject, DefeatableEnemyObject {
	
	// The target of the enemy
	private WorldObject target;
	
	// A timer for throwing things and for motions
	private final Timer throwingCooldown, movingCooldown;
	
	// A motion generator
	private final Random motionGenerator = new Random();
	
	// A factory for the projectiles
	private ProjectileFactory projectileFactory;
	
	/**
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 * - - - - - - - - - - - - Constructors - - - - - - - - - - - 
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 */
	
	public ObjectEnemyToadThrowing(double x, double y) {
		super(Type.SOFT, new AnimatedSetToad(), true, x, y, 24, 32);
		throwingCooldown = new Timer();
		movingCooldown = new Timer();
		projectileFactory = new ProjectileFactory01();
		setAnimation(getAnimationSet().getMoveRightAnimation());
		setTarget(null);
		setMaskFactory(new DefaultMask());
		setImageSpeed(0.25);
	}
	
	/**
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 * - - - - - - - - - - - Public methods - - - - - - - - - - 
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 */
	
	/** Sets the projectile factory for this enemy */
	public void setProjectileFactory(ProjectileFactory projectileFactory) {
		this.projectileFactory = projectileFactory;
	}
	
	/** Returns the projectile factory for this enemy */
	public ProjectileFactory getProjectileFactory() {
		return projectileFactory;
	}
	
	@Override public void performDestructionAction(World world) {
		world.addObjectSynchronized(new ObjectEnemyDead(getAnimationSet().getDeathAnimation(), getX(), getY(), getWidth(), getHeight()));
	}
	
	@Override public void performStepAction(World world) {
		super.performStepAction(world);
		// Addapt to the world physical rules if they are not set
		if (getPhysicalRules() == null)
			setPhysicalRules(world.getPhysicalRules());
		realizeGravity(world);
		// Check if the enemy is in the air
		boolean inAir = world.placeFree(this, getX(), getY() + 2);
		// Focus on a target if the target is not set
		if (getTarget() == null)
			setTarget(world.objectExists(ObjectPlayer.class));
		else 
			moveCharacter(world,inAir);
		// Make the enemy throw things
		if (throwingCooldown.cool()) {
			throwingCooldown.set(30);
			world.addObjectSynchronized(projectileFactory.createProjectile(target, getX(), getY()));
		}
		// Select animation for the enemy
		animateCharacter(inAir);
	}
	
	/**
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 * - - - - - - - - - - Private methods - - - - - - - - - - 
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 */
	
	/** Sets the target of the enemy */
	private void setTarget(WorldObject target) {
		this.target = target;
	}
	
	/** Returns the target of the enemy */
	private WorldObject getTarget() {
		return target;
	}
	
	/** Move the enemy and make the */
	private void moveCharacter(World world, boolean inAir) {
		if (movingCooldown.cool()) {
			movingCooldown.set(60);
			if (motionGenerator.nextBoolean())
				if (motionGenerator.nextBoolean())
					setHorizontalSpeed(1);
				else
					setHorizontalSpeed(-1);
			else
				setHorizontalSpeed(0);
			if (motionGenerator.nextBoolean()) {
				if (!inAir)
					setVerticalSpeed(-8);
			}
		}
		movingCooldown.tick();
		throwingCooldown.tick();
		if (!world.placeFree(this, getX() + getHorizontalSpeed(), getY())) 
			setHorizontalSpeed(-getHorizontalSpeed());
		for (WorldObject obj : world.getObjects()) {
			if (obj instanceof ObjectEnemyToadCollider && collision(obj)) {
				// Move to the previous x-position if a collision occurs with a collider
				setX(getX() - getHorizontalSpeed()); 
				setHorizontalSpeed(-getHorizontalSpeed());
			}
		}
	}
	
	/** Select the animation for the enemy */
	private void animateCharacter(boolean  inAir) {
		if (getTarget().getX() > getX()) {
			if (inAir)
				setAnimation(getAnimationSet().getJumpRightAnimation());
			else if (getHorizontalSpeed() == 0)
				setAnimation(getAnimationSet().getStandRightAnimation());
			else
				setAnimation(getAnimationSet().getMoveRightAnimation());
		} else {
			if (inAir)
				setAnimation(getAnimationSet().getJumpLeftAnimation());
			else if (getHorizontalSpeed() == 0)
				setAnimation(getAnimationSet().getStandLeftAnimation());
			else
				setAnimation(getAnimationSet().getMoveLeftAnimation());
		}
	}
	
	/**
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 * - - - - - - - - - - Private classes - - - - - - - - - - -
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	 */
	
	/** Defines the default mask for the enemy*/
	private class DefaultMask implements ShapeFactory {
		
		public Shape makeShape(double x, double y, double width, double height) {
			return new Rectangle2D.Double(x+8,y+8,width-16,height-8);
		}
		
	}
	
}
